/* Copyright 2020,2022 NXP
 *
 * NXP Confidential. This software is owned or controlled by NXP and may only
 * be used strictly in accordance with the applicable license terms.  By
 * expressly accepting such terms or by downloading, installing, activating
 * and/or otherwise using the software, you are agreeing that you have read,
 * and that you agree to comply with and are bound by, such license terms.  If
 * you do not agree to be bound by the applicable license terms, then you may
 * not retain, install, activate or otherwise use the software.
 */

//#include <AppInternal.h>
#include <SwupApi.h>
#include "SwupUCI.h"
#include <Swup_update.h>
#include "phNxpLogApis_Swup.h"
#include <phTmlUwb_transport.h>

#define RESPONSE_BUFF_SIZE 256

#define LOG_TLV(TAG, PTR)                                               \
    for (size_t i = 0; i < *(PTR + 1) && i < RESPONSE_BUFF_SIZE; i++) { \
        ch += sprintf(ch, "%d.", *(PTR + 2 + i));                       \
    }                                                                   \
    if (*(PTR + 1) > 0x00) {                                            \
        *(ch - 1) = 0x00;                                               \
    }                                                                   \
    LOG_I("%s: %s", TAG, (char *)&buffer[0]);                           \
    phOsalUwb_SetMemory(buffer, 0, sizeof(buffer));                     \
    ch    = &buffer[0];                                                 \
    (PTR) = (PTR) + (*(PTR + 1)) + 2;

tUWBAPI_STATUS Uci_PrintDeviceInfo(uint32_t *fwVersion, uint32_t *dspVersion)
{
    uint8_t resp[RESPONSE_BUFF_SIZE]   = {0};
    uint16_t resp_len                  = 0;
    uint8_t uci_command_get_dev_info[] = {0x20, 0x02, 0x00, 0x00};
    int retry_count                    = 0;
    tUWBAPI_STATUS retStatus           = UWBAPI_STATUS_FAILED;
    char buffer[RESPONSE_BUFF_SIZE]    = {0};
    char *ch;
    uint8_t *payload;
    char deviceName[8] = {0};
    uint16_t uci_command_get_dev_info_length;

    *fwVersion                      = 0;
    *dspVersion                     = 0;
    uci_command_get_dev_info_length = sizeof(uci_command_get_dev_info);
    payload                         = &resp[4];
    ch                              = &buffer[0];

resend_command:
    if (uci_command_get_dev_info_length !=
        phTmlUwb_uci_write(uci_command_get_dev_info, uci_command_get_dev_info_length)) {
        goto cleanup;
    }

retry:
    if (retry_count > 4) {
        goto cleanup;
    }
    resp_len = phTmlUwb_uci_read(resp, RESPONSE_BUFF_SIZE);
    if ((*resp == 0x60) && (*(resp + 1) == 0x01) && (*(resp + 4) == 0xFC)) {
        /* Resend previous frame */
        goto resend_command;
    }
    else if ((*resp == 0x40) && (*(resp + 1) == 0x02) && resp_len > 0) {
        /* Good */
    }
    else {
        phOsalUwb_Delay(100);
        retry_count++;
        goto retry;
    }

    retStatus = UWBAPI_STATUS_OK;
    LOG_I("--------------Device Info--------------");
    if (*payload != 0x00) {
        LOG_E("Device Status               : 0x%02X", *payload);
        goto cleanup;
    }

    payload++;
    LOG_I("Generic UciVersion      : %d.%d", (*payload), (*(payload + 1)));
    payload += 2;
    LOG_I("Mac version             : %d.%d", (*payload), (*(payload + 1)));
    payload += 2;
    LOG_I("Phy version             : %d.%d", (*payload), (*(payload + 1)));
    payload += 2;
    LOG_I("Test version            : %d.%d", (*payload), (*(payload + 1)));
    payload += 17;

    phOsalUwb_MemCopy(deviceName, payload, *(payload + 1));
    LOG_I("DeviceName             : %s", deviceName); /* Tag E3 */
    payload += *(payload + 1) + 2;
    *fwVersion = (uint32_t)(*(payload + 2) << (8 * 2)) | (*(payload + 3) << (8 * 1)) | (*(payload + 4) << (8 * 0));
    LOG_TLV("FirmwareVersion        ", payload); /* Tag E4 */
    LOG_TLV("DeviceVersion          ", payload); /* Tag E5 */
    LOG_TLV("SerialNumber           ", payload); /* Tag E6 */
    *dspVersion = (uint32_t)(*(payload + 2) << (8 * 2)) | (*(payload + 3) << (8 * 1)) | (*(payload + 4) << (8 * 0));
    LOG_TLV("dspVersion             ", payload); /* Tag E7 */
    LOG_TLV("Ranger4Version         ", payload); /* Tag E8 */
    LOG_TLV("CCCVersion             ", payload); /* Tag E9 */

cleanup:
    return retStatus;
}

tUWBAPI_STATUS Uci_EnableSwup()
{
    uint8_t resp[256] = {0};

    uint16_t resp_len                       = 0;
    uint8_t uci_command_enable_swup[]       = {0x2E, 0x12, 0x00, 0x01, 0x00};
    uint16_t uci_command_enable_swup_length = sizeof(uci_command_enable_swup);
    int retry_count                         = 0;
    tUWBAPI_STATUS retStatus                = UWBAPI_STATUS_FAILED;

resend_command:
    if (uci_command_enable_swup_length != phTmlUwb_uci_write(uci_command_enable_swup, uci_command_enable_swup_length)) {
        /* Read out buffer and retry */
        resp_len = phTmlUwb_uci_read(resp, RESPONSE_BUFF_SIZE);
        LOG_AU8_I(resp, resp_len);
        if (uci_command_enable_swup_length !=
            phTmlUwb_uci_write(uci_command_enable_swup, uci_command_enable_swup_length)) {
            goto cleanup;
        }
    }

retry:
    if (retry_count > 4) {
        goto cleanup;
    }
    resp_len = phTmlUwb_uci_read(resp, RESPONSE_BUFF_SIZE);
    if (resp_len == 4) {
        goto resend_command;
    }
    if ((*resp == 0x60) && (*(resp + 1) == 0x01) && (*(resp + 4) == 0xFC)) {
        /* Device is in HPD Resend previous frame */
        goto resend_command;
    }
    else if (resp_len == 0x05 && (*resp == 0x4E) && (*(resp + 1) == 0x12)) {
        /* Good. Response from 0.2.0 FW Onwards */
    }
    else if (resp_len == 0x05 && (*resp == 0x40) && (*(resp + 1) == 0x00)) {
        /* Good. Response from 0.1.0 FW */
    }
    else {
        phOsalUwb_Delay(100);
        retry_count++;
        goto retry;
    }

    if (*(resp + 3) == 0x01 && *(resp + 4) == 0x00) {
        /* Good. Success. */
        retStatus = UWBAPI_STATUS_OK;
    }
    else {
        LOG_E("SWUP Activate failed");
        retStatus = UWBAPI_STATUS_FAILED;
    }

cleanup:
    return retStatus;
}

tUWBAPI_STATUS Uci_PrintCoreCapabilities()
{
    uint8_t resp[256] = {0};

    uint16_t resp_len                    = 0;
    uint8_t uci_command_get_caps[]       = {0x20, 0x03, 0x00, 0x00};
    uint16_t uci_command_get_caps_length = sizeof(uci_command_get_caps);
    int retry_count                      = 0;
    tUWBAPI_STATUS retStatus             = UWBAPI_STATUS_FAILED;
    char buffer[256]                     = {0};
    char *ch                             = &buffer[0];
    uint8_t *payload                     = resp;

resend_cmd:
    if (uci_command_get_caps_length != phTmlUwb_uci_write(uci_command_get_caps, uci_command_get_caps_length)) {
        goto cleanup;
    }

retry:
    if (retry_count > 4) {
        goto cleanup;
    }
    resp_len = phTmlUwb_uci_read(resp, RESPONSE_BUFF_SIZE);
    if (resp_len <= 4) {
        goto resend_cmd;
    }
    else if ((*resp == 0x60) && (*(resp + 1) == 0x01) && (*(resp + 4) == 0xFC)) {
        /* Device is in HPD Resend previous frame */
        goto resend_cmd;
    }
    else if (resp_len == 46 && (*resp == 0x40) && (*(resp + 1) == 0x03)) {
        /*Good*/
    }
    else {
        phOsalUwb_Delay(100);
        retry_count++;
        goto retry;
    }

    payload = payload + 4 + 1;

    LOG_I("--------------Device Core Capabilities--------------");
    LOG_TLV("A0                     ", payload); /* Tag A1 */
    LOG_TLV("A1                     ", payload); /* Tag A1 */
    LOG_TLV("A2                     ", payload); /* Tag A2 */
    LOG_TLV("MAX_PAYLOAD_LEN        ", payload); /* Tag E3 */
    LOG_TLV("MIN_SLOT_LEN           ", payload); /* Tag E4 */
    LOG_TLV("MAX_SESSION_NUM        ", payload); /* Tag E5 */
    LOG_TLV("MAX_ANCHOR_NUM         ", payload); /* Tag E6 */
    LOG_TLV("MIN_UWB_FREQ           ", payload); /* Tag E7 */
    LOG_TLV("MAX_UWB_FREQ           ", payload); /* Tag E8 */

cleanup:
    return retStatus;
}
